home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / MISC / DTMFF110 / DMA_CODE.ASM < prev    next >
Assembly Source File  |  1996-03-10  |  14KB  |  344 lines

  1.         IDEAL
  2.         Model medium
  3.  
  4. ;+---------------------------------------------------------------------------+
  5. ;|  IBM-PC(tm) compatible programmer's DMA library                           |
  6. ;|  Version 1.1                                                              |
  7. ;+---------------------------------------------------------------------------+
  8. ;|  Copyright (C) 1992, Heath I Hunnicutt                                    |
  9. ;+---------------------------------------------------------------------------+
  10. ;|  Thanks to: Gary Nemirovsky                                               |
  11. ;+---------------------------------------------------------------------------+
  12. ;|  This document is for free public distribution.  It is unlawful to        |
  13. ;|  sell this document, or any work based substantially upon it.             |
  14. ;+---------------------------------------------------------------------------+
  15. ;|  This assembly code defines 3 functions that are intended for use         |
  16. ;|  by C programmers in code that requires access to the DMA system.         |
  17. ;|                                                                           |
  18. ;|  DMA transfers occur asynchronously to the CPU's activity, so they        |
  19. ;|  are quite efficient.                                                     |
  20. ;|                                                                           |
  21. ;|  The general sequence for using the DMA is:                               |
  22. ;|      int channel=1;                                                       |
  23. ;|      if (dma_reset(channel))                                              |
  24. ;|              abort();                                                     |
  25. ;|      if (dma_setup(channel,(char far *)My_Buffer,sizeof(My_Buffer),1))    |
  26. ;|              abort();                                                     |
  27. ;|      /* Insert "foreground" code here. */                                 |
  28. ;|      while (dma_done(channel)!=-1) {                                      |
  29. ;|              if (dma_errno)                                               |
  30. ;|                      abort();                                             |
  31. ;|      }                                                                    |
  32. ;+---------------------------------------------------------------------------+
  33. ;| Send suggestions, questions, comments, knoweledge to:                     |
  34. ;|          heathh@cco.caltech.edu     (also @tybalt.cco.caltech.edu)        |
  35. ;|          (or hihunn@through.ugcs.caltech.edu  -- not preferred)           |
  36. ;+---------------------------------------------------------------------------+
  37. ;| PUBLIC FUNCTIONS                                                          |
  38. ;| int far dma_reset(int Channel)                                            |
  39. ;| int far dma_setup(int Channel,char far *Buffer,unsigned Length,int Dir)   |
  40. ;| int far dma_done(int Channel)                                             |
  41. ;+---------------------------------------------------------------------------+
  42. ;| PUBLIC DATA                                                               |
  43. ;| int far dma_errno                                                         |
  44. ;| char far *dma_errlist[]                                                   |
  45. ;+---------------------------------------------------------------------------+
  46. ;| How to assemble this code:                                                |
  47. ;|      You'll need Turbo Assembler(tm) from Borland(tm) Internationl        |
  48. ;| TASM /mx /m2 dma_code                                                     |
  49. ;+---------------------------------------------------------------------------+
  50. ;| HISTORY:                                                                  |
  51. ;|   Ver 1.0 - Initial Release                                               |
  52. ;|   Ver 1.1 - Error checking and reporting added to all functions           |
  53. ;|             dma_setup(..) should never crash your system now.             |
  54. ;+---------------------------------------------------------------------------+
  55.  
  56. Status          EQU     08h     ;DMAC status port (read)     \  same port
  57. Command         EQU     08h     ;DMAC command port (write)   /  (read/write)
  58. ;STATUS/COMMAND BYTE:   ("*" represents defaults)
  59. ;  [ 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 ]
  60. ;   Bit 0: Memory-to-memory transfer  0 => disable*
  61. ;                                     1 => enable
  62. ;       1: "Don't Care" if mem-to-mem disabled  (Bit 0==0)*
  63. ;          Channel 0 address hold     0 => disable
  64. ;                                     1 => enable
  65. ;       2: Controller enable          0 => enable*
  66. ;                                     1 => disable
  67. ;       3: "Don't Care" if mem-to-mem enabled (Bit 0==1)
  68. ;          Timing                     0 => Normal?
  69. ;                                     1 => Compressed?
  70. ;       4: Priority                   0 => Fixed?
  71. ;                                     1 => Rotating
  72. ;       5: "Don't care" if compressed timing (Bit 3==1)
  73. ;          Write selection            0 => Late
  74. ;                                     1 => Extended
  75. ;       6: DREQ sense active          0 => High
  76. ;                                     1 => Low
  77. ;       7: DACK sense active          0 => Low
  78. ;                                     1 => High
  79.  
  80. Request         EQU     09h     ;DMAC channel request (write-only)
  81. ;REQUEST BYTE:
  82. ;  [ 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 ]
  83. ;  \__________________/  |  \_____/
  84. ;       Don't care       |     |
  85. ;                        |     +------+  00 = Select channel 0
  86. ;                        |            |  01 = Select channel 1
  87. ;                        |            |  10 = Select channel 2
  88. ;                        |            +  11 = Select channel 3
  89. ;                        +---+ 0 = Reset request bit
  90. ;                            + 1 = Set request bit
  91.  
  92. DMA_Mask        EQU     0Ah     ;DMAC DMA_Mask (write-only)
  93. Mode            EQU     0Bh     ;DMAC mode (read/write)
  94.  
  95.  
  96. byte_ptr        EQU     00ch    ; byte pointer flip-flop
  97.  
  98. addr            EQU     000h    ; per-channel base address
  99. count           EQU     001h    ; per-channel byte count
  100.  
  101. read_cmd        EQU     048h    ; read mode
  102. write_cmd       EQU     044h    ; write mode
  103. set_cmd         EQU     000h    ; DMA_Mask set
  104. reset_cmd       EQU     004h    ; DMA_Mask reset
  105.  
  106. ; dma controller page register table
  107. ; this table maps from channel number to the i/o port number of the
  108. ; page register for that channel
  109.         DATASEG
  110.  
  111. page_table      DW      00087h  ; channel 0
  112.         DW      00083h  ; channel 1
  113.         DW      00081h  ; channel 2
  114.         DW      00082h  ; channel 3
  115.  
  116. ; "Extra" messages are for future compatability with the Virtual DMA
  117. ; specification.
  118. DMA_E0          DB      0
  119. DMA_E1          DB      "Region not in contiguous memory.",0
  120. DMA_E2          DB      "Region crossed a physical alignment boundary.",0
  121. DMA_E3          DB      "Unable to lock pages.",0
  122. DMA_E4          DB      "No buffer available.",0
  123. DMA_E5          DB      "Region too large for buffer.",0
  124. DMA_E6          DB      "Buffer currently in use.",0
  125. DMA_E7          DB      "Invalid memory region.",0
  126. DMA_E8          DB      "Region was not locked.",0
  127. DMA_E9          DB      "Number of physical pages greater than table length.",0
  128. DMA_EA          DB      "Ivalid buffer ID.",0
  129. DMA_EB          DB      "Copy out of buffer range.",0
  130. DMA_EC          DB      "Invalid DMA channel number.",0
  131.  
  132. ; Use DD for far pointers
  133. ;char far *dma_errlist[]
  134. ;_dma_errlist DD DMA_E0, DMA_E1, DMA_E2, DMA_E3, DMA_E4, DMA_E5, DMA_E6, DMA_E7, DMA_E8, DMA_E9, DMA_EA, DMA_EB, DMA_EC
  135.  
  136. ; Use DW for near pointers
  137. ;char *dma_errlist[]
  138. _dma_errlist DW DMA_E0, DMA_E1, DMA_E2, DMA_E3, DMA_E4, DMA_E5, DMA_E6, DMA_E7, DMA_E8, DMA_E9, DMA_EA, DMA_EB, DMA_EC
  139.  
  140. ;int _dma_errno
  141. _dma_errno   DW 0
  142.  
  143. PUBLIC _dma_errlist,_dma_errno
  144.  
  145.         CODESEG
  146. MACRO zero reg
  147.       xor reg,reg
  148. ENDM zero
  149.       
  150. PUBLIC _dma_setup,_dma_reset,_dma_done
  151. ;+---------------------------------------------------------------------------+
  152. ;| int far dma_setup(int Channel,char far *Buffer,unsigned Length,int Dir)   |
  153. ;| ------------------------------------------------------------------------- |
  154. ;| Channel = 0-3  !Channel 0 is often reserved for memory refresh!           |
  155. ;| Buffer  = Address of data to transfer                                     |
  156. ;| Length  = Length of data to transfer                                      |
  157. ;| Dir     = Direction to move bytes.  1 == Out to the BUS (TO the card)     |
  158. ;|                                     0 == In from the BUS and cards.       |
  159. ;| ------------------------------------------------------------------------- |
  160. ;| Returns: 0 if no errors (dma_errno == 0)                                  |
  161. ;|         -1 if errors occured (dma_errno set to indicate error.)           |
  162. ;+---------------------------------------------------------------------------+
  163. PROC _dma_setup FAR
  164. ARG Channel:WORD,Buffer:DWORD,Len:WORD,Dir:WORD
  165.     push bp
  166.     mov  bp,sp
  167.     push bx cx dx si di
  168.     pushf
  169.  
  170.     mov  [_dma_errno],0
  171. ;Convert seg:ofs Buffer to 20-bit physical address
  172. ;Assumes operating in 8086/real-Mode
  173.     mov  bx,[WORD PTR Buffer]
  174.     mov  ax,[WORD PTR Buffer+2]
  175.     mov  cl,4
  176.     rol  ax,cl
  177.     mov  ch,al
  178.     and  al,0F0h
  179.     add  ax,bx
  180.     adc  ch,0
  181.     and  ch,0Fh
  182.     mov  di,ax
  183. ; (ch << 16) + di == The physical buffer base.
  184.  
  185. ;Calculate the port to receive this address
  186.     mov  bx,[Channel]
  187.     cmp  bx,3
  188.      jbe @@OkChannel
  189.     mov  [_dma_errno],0Ch
  190.     mov  ax,-1
  191.      jmp @@ExitPt
  192. @@OkChannel:
  193.     shl  bx,1
  194. ;bx == Port # Channel*2
  195.  
  196. ;Determine which command byte will be written later
  197.     cmp  [WORD PTR Dir],0
  198.      jnz SHORT @@Do_Read
  199.     mov  al,write_cmd
  200.      jmp SHORT @@Do_Mode
  201. @@Do_Read:
  202.     mov  al,read_cmd
  203. @@Do_Mode:
  204.     push cx
  205.     mov  cx,[Channel]
  206.     add  al,cl
  207.     zero ah
  208.     mov  si,ax
  209.     mov  ax,set_cmd
  210.     add  al,cl
  211.     pop  cx
  212.     mov  cl,al
  213. ;si contains READ/WRITE command for DMA controller
  214. ;cl contains confirmation command for DMA controller
  215.  
  216. ;-------------------------------------------------------------------------
  217. ; Calculations have been done ahead of time to minimize time with
  218. ; interrupts disabled.
  219. ;
  220. ; ch:di == physical base address
  221. ;
  222. ; cl == Confirmation command    (Tells DMA we're done bothering it.)
  223. ;
  224. ; bx == I/O port Channel*2      (This is where the address is written)
  225. ;
  226. ; si == Mode command for DMA
  227. ;-------------------------------------------------------------------------
  228.     mov  ax,di              ;Let's check the address to see if we
  229.     add  ax,[Len]           ;span a page boundary with our length
  230.      jnc @@BoundaryOk       ;Do we?
  231.     mov  [_dma_errno],2     ; y: Error #2
  232.     mov  ax,-1              ;    Return -1
  233.      jmp @@ExitPt           ;    See ya...
  234. @@BoundaryOk:                   ; n: Continue with action
  235.     cli                     ;Disable interrupts while mucking with DMA
  236.  
  237. ;The "byte pointer" is also known as the LSB/MSB flip flop.
  238. ;By writing any value to it, the DMA controller registers are prepared
  239. ;to accept the address and length values LSB first.
  240.     mov  dx,byte_ptr        ;Reset byte pointer Flip/flop
  241.     out  dx,al              ;All we have to do is write to it
  242.  
  243.     mov  ax,di              ;ax=LSW of 20-bit address
  244.     mov  dx,bx              ;dx=DMAC Base Address port
  245.     out  dx,al              ;Store LSB
  246.     mov  al,ah
  247.     out  dx,al              ;Store next byte
  248.  
  249.     mov  al,ch              ;al=Page number
  250.     mov  dx,[bx + OFFSET page_table]        ;dx=Port is the "Page index"
  251.     out  dx,al              ;Store the page
  252.  
  253. ;Write length to port Channel*2 + 1
  254.     mov  ax,[Len]
  255.     mov  dx,bx              ;dx=DMAC Base Adress port
  256.     inc  dx                 ;dx=DMAC Count port (1 after Base address)
  257.     out  dx,al              ;Write LSB of Length
  258.     mov  al,ah
  259.     out  dx,al              ;Write MSB
  260.  
  261.     mov  ax,si              ;Load pre-calculated mode
  262.     mov  dx,Mode            ;dx=DMAC mode register
  263.     out  dx,al              ;Write it to the DSP
  264.  
  265.     mov  dx,DMA_Mask        ;dx=DMAX DMA_Mask register
  266.     mov  al,cl              ;al=pre-calulated DMA_Mask value
  267.     out  dx,al              ;Write DMA_Mask
  268.     mov  ax,0               ;Return with no error
  269.  
  270. @@ExitPt:                       ;Restore stack and return
  271.     popf
  272.     pop  di si dx cx bx
  273.     pop  bp
  274.     ret
  275. ENDP _dma_setup
  276.  
  277. ;+---------------------------------------------------------------------------+
  278. ;| int far dma_reset(int Channel)                                            |
  279. ;| ------------------------------------------------------------------------- |
  280. ;| Channel = 0-3                                                             |
  281. ;|         Resets the specified channel.                                     |
  282. ;| ------------------------------------------------------------------------- |
  283. ;| Returns 0 if Ok, -1 and sets dma_errno on error                           |
  284. ;+---------------------------------------------------------------------------+
  285. PROC _dma_reset FAR
  286. ARG Channel:Word
  287.     push bp
  288.     mov  bp,sp
  289.     push dx
  290.     mov  [_dma_errno],0
  291.     cmp  [Channel],3
  292.      jbe @@OkChannel
  293.     mov  [_dma_errno],0Ch
  294.     mov  ax,-1
  295.      jmp @@Exit_Pt
  296. @@OkChannel:
  297.     mov  dx,DMA_Mask
  298.     mov  ax,reset_cmd
  299.     add  ax,[Channel]
  300.     out  dx,al
  301.     mov  ax,0
  302. @@Exit_Pt:
  303.     pop  dx
  304.     pop  bp
  305.     ret
  306. ENDP _dma_reset
  307.  
  308. ;+---------------------------------------------------------------------------+
  309. ;| int far dma_done(Channel)                                                 |
  310. ;| ------------------------------------------------------------------------- |
  311. ;| Channel = 0-4                                                             |
  312. ;| ------------------------------------------------------------------------- |
  313. ;| Returns: -1 if DMA transaction completed                                  |
  314. ;|         (Maybe it returns the number of bytes left to transfer?)          |
  315. ;| dma_errno == 0 if no error, otherwise equals error number                 |
  316. ;+---------------------------------------------------------------------------+
  317. PROC _dma_done FAR
  318. ARG Channel:Word
  319.     push bp
  320.     mov  bp,sp
  321.     pushf
  322.     push dx
  323.     cmp  [Channel],3
  324.      jbe @@OkChannel
  325.     mov  ax,-1
  326.     mov  [_dma_errno],0Ch
  327.      jmp @@Exit_Pt
  328. @@OkChannel:
  329.     mov  dx,[Channel]
  330.     shl  dx,1
  331.     add  dx,count
  332.     cli
  333.     in   al,dx
  334.     mov  ah,al
  335.     in   al,dx
  336.     xchg al,ah
  337. @@Exit_Pt:
  338.     pop  dx
  339.     popf
  340.     pop  bp
  341.     ret
  342. ENDP _dma_done
  343. END
  344.